"""
 GV3 - Copyright CUBE Gestioni S.r.l. 2010

 Formatting functions

 $Id: formatter.py 430 2011-06-22 15:30:42Z andre $

"""

from sqlalchemy import orm
import cgi


def objToDict(obj, pk=True, fk=False, rel=True):
    """
    @brief returns a dict from an obj
    @detailed converts an instance of a model class object into a dictionary
    @param obj object to convert
    @param pk  include Primary Key
    @param fk  include Foreign Keys
    @param rel include Relations to other classes, expanding them with str()
    """
    return dict([(k, "%s" % getattr(obj, k)) for k in modelFields(obj.__class__, pk=pk, fk=fk, rel=rel)])

def modelFields(modelClass, pk=True, fk=True, rel=True):
    """
    @brief returns array of ORM attributes, given a model class
    @param modelClass class to process
    @param pk  include Primary Key
    @param fk  include Foreign Keys
    @param rel include Relations to other classes, expanding them with str()

    """

    fields=[]
    columns=[(k,v) for k,v in modelClass.__dict__.items() if isinstance(v, orm.attributes.InstrumentedAttribute)]

    for name,column in columns:
        if(isinstance(column.property, orm.properties.RelationshipProperty)): #is a relation
            if rel:
                fields.append(name)
            continue

        if(isinstance(column.property, orm.properties.CompositeProperty)):
            fields.append(name)
            continue

        if (modelClass.__table__.c[name].primary_key): # is primary key
            if pk:
                fields.append(name)
            continue

        if(len(modelClass.__table__.c[name].foreign_keys)): # is a foreign key id
            if fk:
                fields.append(name)
            continue

        fields.append(name)
    return fields


# JSON
def JsonItem(obj, pk=True, fk=True, rel=True):
    """
    @brief convert a single record to JSON format
    @param obj instance on model class
    """
    output=[]
    for k,v in objToDict(obj, pk, fk, rel).items():
        output.append(r"%s: '%s'" % (k, v))

    return "{%s}" % (','.join(output))

def Json(query, pk=True, fk=True, rel=True, debug=False):
    """
    @brief convert a query result (a list of records) into a JSON array
    """
    items=[]
    for item in query:
            items.append(JsonItem(item, pk, fk, rel))

    if debug:
        return "[\n\t%s\n]" % (',\n\t'.join(items))
    else:
        return "[%s]" % (','.join(items))

# XML
def XmlItem(obj, indent=0, pk=True, fk=True, rel=True, debug=False):
    """
    @brief convert a single item in a XML record
        <tablename>
           <id>id</id>
           <label>LABEL</label>
        </tablename>
    """
    # if debug:
        # space=' '*(indent*2)
        # dspace='  '+space
    # else:
        # space=dspace=''
    # int(True) == 1, int(False) == 0
    space=' '*int(debug)*(indent*2)
    dspace='  '*int(debug)+space*int(debug)

    xml=[]
    xml.append('%s<%s>' % (space, obj.__class__.__name__))

    for k, v in objToDict(obj, pk=pk, fk=fk, rel=rel).items():
        if debug:
            xml.append('%s<%s>%s</%s>' % (dspace, k, cgi.escape(v), k))
        else:
            xml.append('<%s>%s</%s>' % (k, cgi.escape(v), k))

    xml.append('%s</%s>' % (space, obj.__class__.__name__))

    if debug:
        return '\n'.join(xml)
    else:
        return ''.join(xml)

def Xml(query, pk=True, fk=True, rel=True, debug=False):
    """
    @brief convert a query result (a list of records) in XML
    """
    items=[]

    for item in query:
        items.append(XmlItem(item, debug=debug, indent=1, pk=pk, fk=fk, rel=rel))

    className=query[0].__class__.__name__

    if debug:
        return '<?xml version="1.0" encoding="UTF-8"?>\n<%ss>\n%s\n</%ss>' % (className,
                '\n'.join(items),
                className)
    else:
        return '<?xml version="1.0" encoding="UTF-8"?><%ss>%s</%ss>' % (className, ''.join(items), className)
# CSV
def CsvItem(obj, pk=True, fk=True, rel=True):
    """
    @brief convert a single record to CSV format
    """
    output=[]
    for k,v in objToDict(obj, pk, fk, rel).items():
        output.append(r"%s" % v)
    return ';'.join(output)

def Csv(query, pk=True, fk=True, rel=True):
    """
    @brief convert a query result (a list of records) in CSV
    """
    items=[]
    for item in query:
        items.append(CsvItem(item, pk=pk, fk=fk, rel=rel))
    return "%s\n%s" % (';'.join(modelFields(query[0].__class__, pk, fk, rel)), '\n'.join(items))

# # HTML
# def HTMLOption(self, id='id', label='label', selected=False):
    # """
    # Method to convert a single record to HTML option
    # """
    # if self.__dict__[id] != None:
            # return r"<option value='%s'%s>%s</option>" % (self.__dict__[id],
                    # ['', ' selected="selected"'][selected==True],
                    # h.util.html_escape(self.__dict__[label]))
# @classmethod
# def HTMLOptions(cls, id='id', label='label', value=None, order_by='label', filter_on=None, debug=False):
    # """
    # @brief Return all records as HTML options

    # @detailed Class method (call with model.Class.HTMLOptions()) that returns all records as HTML Options

    # @param id attribute to use as ID
    # @param label attribute to use as Label
    # @param value id of selected record
    # @param order_by attribute to order upon
    # """
    # items=[]
    # for item in cls.all(order_by=order_by, filter_on=filter_on):
        # items.append(item.HTMLOption(id=id, label=label, selected=(item.__dict__[id]==value)))
    # if len(items)>0:
        # # return "<SELECT NAME='%s'>\n\t%s\n</SELECT>" % (cls.__name__, '\n\t'.join(items))
        # return '\n'.join(items)
# # GRID
# def HTMLGridRow(self, **kwargs):
    # return """
    # <tr>
    # <td>%s</td>
    # <td>%s</td>
    # </tr>\n""" % (self.id, self.label, self.__class__.__name__,self.id)

# @classmethod
# def HTMLGrid(cls, debug=False, **kwargs):
    # items=[]
    # for item in cls.all():
        # items.append(item.HTMLGridRow())
    # return "<table>%s</table>" % ''.join(items)


formats = {
        'xml': { 'fn': Xml,
            'fn1': XmlItem,
            'type': ('Content-type', 'text/xml;charset=utf-8') },

        'csv': { 'fn': Csv,
            'fn1': CsvItem,
            'type': ('Content-type', 'text/csv;charset=utf-8') },

        'txt': { 'fn': Csv,
            'fn1': CsvItem,
            'type': ('Content-type', 'text/plain;charset=utf-8') },

        'json': { 'fn': Json,
            'fn1': JsonItem,
            'type': ('Content-type', 'application/json;charset=utf-8') },

        # 'html': { 'fn': HTMLOptions,
            # 'fn1': HTMLOption,
            # 'h': ('Content-type', 'text/html;charset=utf-8') },

        # 'grid': { 'fn': HTMLGrid,
            # 'fn1': HTMLGridRow,
            # 'h': ('Content-type', 'text/html;charset=utf-8') },
        }


def formatQuery(query, format='json', withHeader=False):
    if withHeader:
        return (formats[format]['type'], formats[format]['fn'](query))
    else:
        return formats[format]['fn'](query)

def formatItem(item, format='json', withHeader=False):
    if withHeader:
        return (formats[format]['type'], formats[format]['fn1'](item))
    else:
        return formats[format]['fn1'](item)

format = formatQuery
